﻿using System;
using System.Timers;
using Microsoft.Win32;

namespace EduSpeed
{
    internal class SogouController
    {
        /// <summary>
        /// Environment variable for Sogou Controller
        /// </summary>
        private readonly static string SOGOU_PATH = @"EduNetSpeedExplorer.exe";
        private readonly static string SOGOU_ARGUMENT = @"-proxy";

        /// <summary>
        /// Environment variable for EduSpeed
        /// </summary>
        private static int RUNNING_PROCESS_ID = -1;

        /// <summary>
        /// Timer : Check how much memory used by EXE
        /// </summary>
        readonly Timer watchTimer = new Timer(10000);

        /// <summary>
        /// Constructor
        /// </summary>
        internal SogouController()
        {
            //Try to start EXE
            if (Running())
                return;

            Start();
        }

        /// <summary>
        /// Start EXE
        /// </summary>
        /// <returns>True if success, else False</returns>
        internal bool Start()
        {
            if (Running())
                return true;

            try
            {
                //+ Setp 1
                System.Diagnostics.Process process = new System.Diagnostics.Process { StartInfo = new System.Diagnostics.ProcessStartInfo(SOGOU_PATH, SOGOU_ARGUMENT) };
                process.Start();
                process.WaitForExit(500);

                //+ Setp 2
                System.Diagnostics.Process process2 = new System.Diagnostics.Process { StartInfo = new System.Diagnostics.ProcessStartInfo(SOGOU_PATH, SOGOU_ARGUMENT) };
                process2.Start();
                process2.WaitForExit(3000);

                if (process.HasExited && process2.HasExited)
                    return false;
                else if (process.HasExited)
                    RUNNING_PROCESS_ID = process2.Id;
                else if (process2.HasExited)
                    RUNNING_PROCESS_ID = process.Id;
                else
                    throw new Exception();

                SetWatchTimer();
                StartWatchTimer();

                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// Stop EXE
        /// </summary>
        /// <returns>True if success, else False</returns>
        internal bool Stop()
        {
            if (!Running())
                return true;

            try
            {
                System.Diagnostics.Process process = System.Diagnostics.Process.GetProcessById(RUNNING_PROCESS_ID);
                process.Kill();
                process.WaitForExit(2000);

                if (!process.HasExited)
                    return false;

                StopWatchTimer();
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// Check if EXE is running
        /// </summary>
        /// <returns>True if running, else False</returns>
        internal bool Running()
        {
            try
            {
                System.Diagnostics.Process process = System.Diagnostics.Process.GetProcessById(RUNNING_PROCESS_ID);

                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// Set WatchTimer
        /// </summary>
        private void SetWatchTimer()
        {
            watchTimer.Elapsed += watchTimer_Elapsed;
        }

        /// <summary>
        /// Start WatchTimer
        /// </summary>
        private void StartWatchTimer()
        {
            watchTimer.Start();
        }

        /// <summary>
        /// Stop WatchTimer
        /// </summary>
        private void StopWatchTimer()
        {
            watchTimer.Stop();
        }

        /// <summary>
        /// watchTimer Event: "Elapsed"
        /// </summary>
        private void watchTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            if (!Running())
                return;

            System.Diagnostics.Process process = System.Diagnostics.Process.GetProcessById(RUNNING_PROCESS_ID);

            int c = 0;
            //Memory limit at 256MB, then restart
            while (process.WorkingSet64 > 256 * 1024 * 1024 && c++ < 10)
            {
                if (Stop())
                    Start();

                System.Threading.Thread.Sleep(2000);
            }
        }
    }
}